------------------------
-- Project 1
-- Derek Homan
-- Jason Armstrong
------------------------
--main entity declaration
use work.all;

entity prob21 is
	port(misccontrol: in bit;
		status: out bit;
		clk: out bit;
		ain: in bit_vector(3 downto 0);
		bin: in bit_vector(3 downto 0);
		start : in bit;
		reg2_out: out bit_vector(3 downto 0));
end prob21;



--component declarations/initalizations
--  ALU
  use work.prims.all;
	entity ALU is
		generic(del: time);
		port(a,b: in bit_vector(3 downto 0); ci: in bit;
			fsel: in bit_vector(1 downto 0);
			f: out bit_vector(3 downto 0); cout: out bit);
	end ALU;

	architecture alu_alg of alu is
	begin
		process(a,b,ci,fsel)
			variable fv : bit_vector(3 downto 0);
			variable coutv: bit;
		begin
			case fsel is
				when "00" => f <= a after del;
				when "01" => f <= not(a) after del;
				when "10" => add(a,b,ci,fv,coutv);
										f <= fv after del;
										cout <= coutv after del;
				when "11" => f <= a and b after del;
			end case;
		end process;
	end alu_alg;
--  OSC
	entity osc is
		generic(hitime, lowtime: TIME);
		port(RUN: in bit; clk: out bit);
	end osc;

	architecture osc_beh of osc is
	begin
		process
		begin
			--wait until RUN = '1';
			while RUN = '1' loop
				clk <= '1';
				wait for hitime;
				clk <= '0';
				wait for lowtime;
			end loop;
		end process;
	end osc_beh;
--  RAM
  use work.prims.all;
	entity ram is
		generic (rdel, disdel: time);
		port(data: inout bit_vector(3 downto 0);
				address: in bit_vector(4 downto 0);
				rd,wr,ncs: in bit);
	end ram;


	architecture simple_ram of ram is
		type MEMORY is array(0 to 31) of bit_vector(3 downto 0);
	begin
		process(rd,wr,ncs,address,data)
			variable mem: MEMORY;
		begin
			if ncs='0' then
				if rd='1' then
					data <= mem(intval(address)) after rdel;
				elsif wr='1' then
					mem(intval(address)) := data;
				end if;
			else
				data <= "1111" after disdel;
			end if;
		end process;
	end simple_ram;

--  Register
	entity reg is
		generic(del: time);
		port(reset, load, clk: in bit;
				data_in: in bit_vector(3 downto 0);
				q: inout bit_vector(3 downto 0));
	end reg;

	architecture reg_beh of reg is
	begin
		reg: block(not clk'stable and clk='1')
		begin
			q <= guarded "0000" after del when reset = '1' else
				data_in after del when load='1' else
				q;
		end block reg;
	end reg_beh;

-- Multiplexor
	entity mux4_1 is
		generic(del: time);
		port(in0, in1, in2, in3: in bit_vector(3 downto 0);
				sel: in bit_vector(1 downto 0);
				o : out bit_vector(3 downto 0));
	end mux4_1;

	architecture mux4_1_df of mux4_1 is
	begin
		o <= in0 after del when sel = "00" else
				 in1 after del when sel = "01" else
				 in2 after del when sel = "10" else
				 in3 after del;
	end mux4_1_df;
  
--cntrl_logic/cntrl_mem/data_unit
	entity cntrl_logic is
		generic(del: time);
		port(op: in bit;
				clk: in bit;
				start: in bit;
				addr: out bit_vector(3 downto 0));
	end cntrl_logic;

	architecture cntrl_logic_beh of cntrl_logic is
		signal state : bit_vector(2 downto 0) := "000";
		signal next_state: bit_vector(2 downto 0) := "000";
	begin
		process(op,clk, state, start)
		begin
			if(clk'event and clk='1')then
			  if(start = '1') then
				  if(op = '0')then --a xor b
  					case state is
  						when "000" =>
  							next_state <= "001";
							addr <= '0' & state;
						when "001" =>
							next_state <= "010";
							addr <= '0' & state;
						when "010" =>
							next_state <= "011";
							addr <= '0' & state;
						when "011" =>
							next_state <= "100";
							addr <= '0' & state;
						when "100" =>
							next_state <= "101";
							addr <= '0' & state;
						when "101" =>
							next_state <= "110";
							addr <= '0' & state;
						when "110" =>
							next_state <= "111";
							addr <= '0' & state;
						when "111" =>
							next_state <= "000";
							addr <= '0' & state;
					end case;
				else -- 2*(a-b)
					case state is
						when "000" =>
							next_state <= "001";
							addr <= '1' & state;
						when "001" =>
							next_state <= "010";
							addr <= '1' & state;
						when "010" =>
							next_state <= "011";
							addr <= '1' & state;
						when "011" =>
							next_state <= "100";
							addr <= '1' & state;
						when "100" =>
							next_state <= "101";
							addr <= '1' & state;
						when "101" =>
							next_state <= "110";
							addr <= '1' & state;
						when "110" =>
							next_state <= "111";
							addr <= '1' & state;
						when "111" =>
							next_state <= "000";
							addr <= '1' & state;
					end case;
				end if;
				else
				  next_state <= "000";
				end if;
			end if;
		end process;
		state <= next_state;
	end cntrl_logic_beh;
	
	entity cntrl_mem is
		generic(del: time);
		port(addr : in bit_vector(3 downto 0);
				control_lines: out bit_vector(7 downto 0);
				status: out bit);
	end cntrl_mem;

	architecture cntrl_mem_beh of cntrl_mem is
	begin
		process(addr)
		begin
			case addr is
			  --xor
				when "0000" =>
					control_lines <= "01000000"; -- 1 = not a
					status <= '0' after del;
				when "0001" =>
					control_lines <= "01101000"; -- 2 = not b
					status <= '0' after del;
				when "0010" =>
					control_lines <= "11010110"; -- 1 = 1 and 2
					status <= '0' after del;
				when "0011" =>
					control_lines <= "01010000"; -- 1 = not 1
					status <= '0' after del;
				when "0100" =>
					control_lines <= "11100010"; -- 2 = a and b
					status <= '0' after del;
				when "0101" =>
					control_lines <= "01111000"; -- 2 = not 2
					status <= '0' after del;
				when "0110" =>
					control_lines <= "11110110"; -- 2 = 1 and 2
					status <= '0' after del;
				when "0111" =>
					control_lines <= "00010000";
					status <= '1' after del;
				--2(a-b)
				when "1000" =>
					control_lines <= "01001000"; -- 1 = not b
					status <= '0' after del;
				when "1001" =>
					control_lines <= "10000101"; -- 1 = a + 1 + (cin=1)
					status <= '0' after del;
				when "1010" =>
					control_lines <= "10110100"; -- 2 = 1 + 1
					status <= '0' after del;
				when "1011" =>
					control_lines <= "00010000";
					status <= '1' after del;
				when "1100" =>
					control_lines <= "00010000";
					status <= '1' after del;
				when "1101" =>
					control_lines <= "00010000";
					status <= '1' after del;
				when "1110" =>
					control_lines <= "00010000";
					status <= '1' after del;
				when "1111" =>
					control_lines <= "00010000";
					status <= '1' after del;
			end case;
		end process;
	end cntrl_mem_beh;


--main entity architecture
	--TODO
	architecture alg of prob21 is
		component osc
			generic(hitime, lowtime: TIME);
			port(run: in bit; clk: out bit);
		end component;
		component ALU
		  generic(del: time);
		  port(a,b: in bit_vector(3 downto 0); ci: in bit;
			     fsel: in bit_vector(1 downto 0);
			     f: out bit_vector(3 downto 0); cout: out bit);
		end component;
		component cntrl_mem
		  	 generic(del: time);
		    port(addr : in bit_vector(3 downto 0);
				    control_lines: out bit_vector(7 downto 0);
				    status: out bit);
		end component;
		component cntrl_logic
		    generic(del: time);
		    port(op: in bit; clk: in bit; start : in bit;
				      addr: out bit_vector(3 downto 0));
	  end component;
	  component mux4_1
	      generic(del: time);
		    port(in0, in1, in2, in3: in bit_vector(3 downto 0);
				    sel: in bit_vector(1 downto 0);
				    o : out bit_vector(3 downto 0));
	  end component;
	  component reg
	    	 generic(del: time);
		    port(reset, load, clk: in bit;
				    data_in: in bit_vector(3 downto 0);
				    q: inout bit_vector(3 downto 0));
	  end component;
	  component simple_ram
	      generic (rdel, disdel: time);
		    port(data: inout bit_vector(3 downto 0);
				    address: in bit_vector(4 downto 0);
				    rd,wr,ncs: in bit);
		end component;
		  
		for all: osc use entity work.osc;
    for all: ALU use entity work.ALU;
    for all: cntrl_mem use entity work.cntrl_mem;
    for all: cntrl_logic use entity work.cntrl_logic;
    for all: mux4_1 use entity work.mux4_1;
    for all: reg use entity work.reg;
    

		signal clksig : bit;
		signal muxasig : bit_vector(3 downto 0);
		signal muxbsig : bit_vector(3 downto 0);
		signal csig : bit_vector(7 downto 0);
		signal aluout : bit_vector(3 downto 0);
		signal rega : bit_vector(3 downto 0);
		signal regb : bit_vector(3 downto 0);
		signal reg1 : bit_vector(3 downto 0);
		signal reg2 : bit_vector(3 downto 0);
		signal addr: bit_vector(3 downto 0);
		signal ncsig5: bit;
	begin
	  ncsig5 <= not csig(5) after 6 ns;
	  clk <= clksig;
	  reg2_out <= reg2;
	  reg1_out <= reg1;
	  addr_out <= addr;
	  osc0: osc
	   generic map(40 ns, 40 ns)
	   port map('1', clksig);
	  alu0: alu
	   generic map(6 ns)
	   port map(muxasig, muxbsig, csig(0), csig(7 downto 6), aluout);
	  muxa: mux4_1
	   generic map(0 ns)
	   port map(ain, bin, reg1, reg2, csig(4 downto 3), muxasig);
	  muxb: mux4_1
	   generic map(0 ns)
	   port map(ain, bin, reg1, reg2, csig(2 downto 1), muxbsig);
	  reg_a: reg
	   generic map(6 ns)
	   port map('0', '1', clksig, ain, rega);
	  reg_b: reg
	   generic map(6 ns)
	   port map('0', '1', clksig, bin, regb);
	  reg_1: reg
	   generic map(6 ns)
	   port map('0', ncsig5, clksig, aluout, reg1);
	  reg_2: reg
	   generic map(6 ns)
	   port map('0', csig(5), clksig, aluout, reg2);
    cn_mem: cntrl_mem
     generic map(15 ns)
     port map(addr, csig, status);
    cn_logic: cntrl_logic
     generic map(6 ns)
     port map(misccontrol, clksig, start, addr);
	end alg;
